package samples;

import its.util.RandomFactory;

import java.util.ArrayList;
import java.util.List;

import samples.objectivefunctions.PatternFunction;
import engine.Algorithm;
import engine.CachedObjectiveFunction;
import engine.Population;
import engine.SingleThreadedEvaluator;
import engine.exitcriteria.AllIndividualsAreSimilar;
import engine.exitcriteria.MaxIterations;
import engine.individuals.NaturalVectorIndividual;
import engine.operators.CombineOperators;
import engine.operators.CombineOperatorsWithEvaluation;
import engine.operators.ReportStatisticsOperator;
import engine.operators.RouletteReproduction;
import engine.operators.WorstHalfCutoff;
import engine.operators.natural.NaturalConstrainedMutation;
import engine.operators.natural.NaturalMeanCrossover;
import engine.utils.ListUtils;

public class SGA {

	private static final int MAX_ITERATIONS  = 50;
	private static final int POPULATION_SIZE = 50;
	private static final int CHROMOSOME_SIZE = 12;
	private static final int TASK_CONSTRAINT = 63;
	
	@SuppressWarnings("unchecked")
	public void run() {
		
		Population<NaturalVectorIndividual> population = initializePopulation();
		
		Algorithm<NaturalVectorIndividual> alg =
      new Algorithm<NaturalVectorIndividual>(population);
		
		CachedObjectiveFunction<NaturalVectorIndividual> objectiveFunctionWrapper = 
			new CachedObjectiveFunction<NaturalVectorIndividual>(
				new PatternFunction(new long[] { 0L, 0L, 32L, 31L, 0L, 0L, 32L, 31L, 0L, 0L, 32L, 31L, }));
		
//		alg
//				.addEvaluationPoint(evaluator);
		
		alg.addExitPoint(new MaxIterations<NaturalVectorIndividual>(MAX_ITERATIONS));
		
		alg.addExitPoint(
				new AllIndividualsAreSimilar<NaturalVectorIndividual>(objectiveFunctionWrapper));
		
		
//		EvolutionParams params = new EvolutionParams();
//		params.tournamentSize = 6;
//		alg.addOperator(new TournamentSelectionOperator<NaturalVectorIndividual>(
//				objectiveFunctionWrapper, params));
		SingleThreadedEvaluator<NaturalVectorIndividual> evaluator = new SingleThreadedEvaluator<NaturalVectorIndividual>(
				ListUtils.buildList(objectiveFunctionWrapper));
		
		CombineOperators<NaturalVectorIndividual> mainLogic =
			new CombineOperators<NaturalVectorIndividual>(
					new RouletteReproduction<NaturalVectorIndividual>(objectiveFunctionWrapper),
					new NaturalMeanCrossover(),
					new NaturalConstrainedMutation(0.1));
		
		alg.addOperator(new CombineOperatorsWithEvaluation<NaturalVectorIndividual>(
				mainLogic,
				evaluator,
				new WorstHalfCutoff<NaturalVectorIndividual>(objectiveFunctionWrapper)));
		
		ReportStatisticsOperator<NaturalVectorIndividual> reporter = new ReportStatisticsOperator<NaturalVectorIndividual>(
				objectiveFunctionWrapper);
		
		alg.addOperator(reporter);
		
		// preparing - evaluating before run
		evaluator.apply(population);
		// report population before run
		reporter.apply(population);
		
		alg.run();
		
	}

	private Population<NaturalVectorIndividual> initializePopulation() {
		List<NaturalVectorIndividual> instances = new ArrayList<NaturalVectorIndividual>(POPULATION_SIZE);
		
		for (int i = 0; i < POPULATION_SIZE; i++) {
			NaturalVectorIndividual individual = 
				new NaturalVectorIndividual(CHROMOSOME_SIZE);
			for (int j = 0; j < CHROMOSOME_SIZE / 4; ++j) {
				individual.set(RandomFactory.getNextInt(4) + j * 4,
						(long) TASK_CONSTRAINT);
			}
			instances.add(individual);
		}
		return new Population<NaturalVectorIndividual>(instances);
	}
	
	public static void main(String[] args) {
		new SGA().run();
	}
}
